{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this tutorial we'll learn how to build a compound widget of the [Gaussian Density](Gaussian%20Density.ipynb) example. \n",
    "\n",
    "Steps to build a compound widget:\n",
    "1. Create a class and extend it from DOMWidget or its subclasses. (If you are building a dashboard for example using HBox, VBox etc. then it makes sense to extend the class from Box, HBox or VBox as needed)\n",
    "2. Inside the class constructor call the super class constructor passing in the widgets as children\n",
    "3. Register any widget callbacks inside the constructor and define callbacks as class methods\n",
    "\n",
    "Once the compound widget is defined in a class, it can be put in a library and used along with other interactive widgets! Compound widgets are an excellent way of building re-usable components (**using just python code**) which can be seamlessly integrated with `ipywidgets`, `bqplot` and other interactive widgets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.stats import norm\n",
    "\n",
    "import ipywidgets as widgets\n",
    "import bqplot.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# extend the class from layout class VBox\n",
    "class GaussianDensity(widgets.VBox):\n",
    "    def __init__(self, *args, **kwargs):        \n",
    "        x = np.linspace(-10, 10, 200)\n",
    "        y = norm.pdf(x)\n",
    "\n",
    "        # gaussian density figure\n",
    "        self.title_tmpl = 'Gaussian Density (mu = {} and sigma = {})'\n",
    "        self.pdf_fig = plt.figure(title=self.title_tmpl.format(0, 1), \n",
    "                                  layout=widgets.Layout(width='800px', height='600px'))\n",
    "        self.pdf_line = plt.plot(x, y, 'm', stroke_width=3)\n",
    "        \n",
    "        # sliders for mu and sigma        \n",
    "        self.mu_slider = widgets.FloatSlider(description='$\\mu$', value=0, min=-5, max=5, step=.1)\n",
    "        self.sigma_slider = widgets.FloatSlider(description='$\\sigma$', value=1, min=0.1, max=5, step=.1)\n",
    "        slider_layout = widgets.HBox([self.mu_slider, self.sigma_slider])\n",
    "        \n",
    "        # register callback with the 'value' trait of the sliders\n",
    "        for slider in [self.mu_slider, self.sigma_slider]:\n",
    "            slider.observe(self.update_density, 'value')\n",
    "        \n",
    "        # call super construction by passing in the widgets as children\n",
    "        super(GaussianDensity, self).__init__(children=[self.pdf_fig, slider_layout])\n",
    "    \n",
    "    def update_density(self, change):\n",
    "        new_mu = self.mu_slider.value\n",
    "        new_sigma = self.sigma_slider.value\n",
    "        # update the y attribute of the plot with the new pdf\n",
    "        # computed using new mu and sigma values\n",
    "        self.pdf_line.y = norm.pdf(self.pdf_line.x, new_mu, new_sigma)\n",
    "\n",
    "        # also update the fig title\n",
    "        self.pdf_fig.title = self.title_tmpl.format(new_mu, new_sigma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gaussian_density_widget = GaussianDensity()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# render the compund widget like any other interactive widget\n",
    "gaussian_density_widget"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# we can stack this compound widget together with other interactive widgets\n",
    "widgets.HBox([gaussian_density_widget, widgets.IntSlider()])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
